﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NHibernateSample.Domain.Entities;
using NHibernate;
using NUnit.Framework;

namespace NHibernateSample.DAL.Test
{

    [TestFixture]
    public class LazyLoadingFixture
    {
        private NHibernateHelper _helper;
        private LazyLoading _lazyLoading;
        [TestFixtureSetUp]
        public void TestFixtureSetup()
        {
            _helper = new NHibernateHelper();
            HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize();
        }

        [SetUp]
        public void Setup()
        {
            _lazyLoading = new LazyLoading(_helper.GetSession());
        }

         #region LazyLoad
       /// <summary>
        /// 1.默认延迟加载
        /// 调用数据访问层中的LazyLoad方法加载一个Customer对象，NHibernate的默认延迟加载Customer关联的Order对象。利用NHibernate提供有用类(NHibernateUtil)测试被关联的Customer对象集合是否已初始化(也就是已加载)。
        /// </summary>
        [Test]
        public void LazyLoadTest()
        {
            Customer customer = _lazyLoading.LazyLoad(1);
            Assert.IsFalse(NHibernateUtil.IsInitialized(customer.Orders));
        }

        /// <summary>
        /// 2.延迟加载并关闭Session
        /// 调用使用Using强制资源清理Session加载Customer对象的方法。
        /// </summary>
        [Test]
        public void LazyLoadUsingSessionTest()
        {
            Customer customer = _lazyLoading.LazyLoadUsingSession(1);
            Assert.IsFalse(NHibernateUtil.IsInitialized(customer.Orders));
        }

        /// <summary>
        /// 1.默认延迟加载
        /// 调用数据访问层中的LazyLoadOrderAggregate方法加载一个Order对象，NHibernate的默认延迟加载Order关联的Products对象集合(多对多关系)，利用代理模式加载Customer对象集合(多对一关系)。利用NHibernate提供有用类(NHibernateUtil)测试被关联的Products对象集合和Customer对象集合是否已初始化。
        /// </summary>
        [Test]
        public void LazyLoadOrderAggregateTest()
        {
            Order order = _lazyLoading.LazyLoadOrderAggregate(2);
            Assert.IsFalse(NHibernateUtil.IsInitialized(order.Customer));
            Assert.IsFalse(NHibernateUtil.IsInitialized(order.Products));
        }

        /// <summary>
        /// 2.延迟加载并关闭Session
        /// 使用Using强制资源清理Session加载Order对象的方法。
        /// </summary>
        [Test]
        public void LazyLoadOrderAggregateUsingSessionTest()
        {
            Order order = _lazyLoading.LazyLoadOrderAggregateUsingSession(2);
            Assert.IsFalse(NHibernateUtil.IsInitialized(order.Customer));
            Assert.IsFalse(NHibernateUtil.IsInitialized(order.Products));
        }

        /// <summary>
        /// 3.延迟加载中LazyInitializationException异常
        /// 如果我想在Session清理关闭之后访问Order对象中的某些项会得到一个异常，由于session关闭，NHibernate不能为我们延迟加载Order项
        /// </summary>
        [Test]
        [ExpectedException(typeof(LazyInitializationException))]
        public void LazyLoadOrderAggregateUsingSessionOnFailTest()
        {
            //测试抛出“Could not initialize proxy - no Session”预计的LazyInitializationException异常，表明测试成功，证明不能加载Order对象的Customer对象。
            Order order = _lazyLoading.LazyLoadOrderAggregateUsingSession(2);
            string name = order.Customer.Name.FullName;
        }

        /// <summary>
        /// 4.N+1选择问题
        /// 我们在加载Order后访问Product项，导致访问Product每项就会产生一个选择语句
        /// </summary>
        [Test]
        public void LazyLoadOrderAggregateSelectBehaviorTest()
        {
            Order order = _lazyLoading.LazyLoadOrderAggregate(2);
            float sum = 0.0F;
            foreach (var item in order.Products)
            {
                sum += item.Cost;
            }
            Assert.AreEqual(15.0F, sum);
        }
        #endregion LazyLoad


        #region 立即加载
        #region 一对多关系
        /// <summary>
        /// 1.使用lazy="false"属性
        /// 这里介绍第一种方法就是修改映射文件来立即加载，打开Customer.hbm.xml文件，在Set元素中添加lazy="false"。
        /// </summary>
        [Test]
        public void EagerLoadUsingLazyFalseTest()
        {
            Customer customer = _lazyLoading.LazyLoadUsingSession(1);
            Assert.IsTrue(NHibernateUtil.IsInitialized(customer.Orders));
        }

        /// <summary>
        /// 2.使用NHibernateUtil实用类
        /// NHibernate提供实用类(NHibernateUtil)不光光只是用来测试被关联的对象集合是否已初始化，还有一个非常重要的功能就是可以强制初始化未初始化的相关联的对象。
        /// </summary>
        [Test]
        public void EagerLoadUsingSessionAndNHibernateUtilTest()
        {
            Customer customer = _lazyLoading.EagerLoadUsingSessionAndNHibernateUtil(1);
            Assert.IsTrue(NHibernateUtil.IsInitialized(customer.Orders));
        }
        #endregion

        #region 多对多关系
        /// <summary>
        /// 2.使用NHibernateUtil实用类
        /// 如果你需要获得Order实体的相关联对象可以使用NHibernateUtil类初始化关联对象(把他们从数据库取出来)。
        /// </summary>
        [Test]
        public void EagerLoadOrderAggregateSessionAndNHibernateUtilTest()
        {
            Order order = _lazyLoading.EagerLoadOrderAggregateSessionAndNHibernateUtil(2);
            Assert.IsTrue(NHibernateUtil.IsInitialized(order.Customer));
            Assert.IsTrue(NHibernateUtil.IsInitialized(order.Products));
            Assert.AreEqual(order.Products.Count, 2);
        }
        #endregion

        //3.使用HQL抓取策略
        [Test]
        public void EagerLoadOrderAggregateWithHQLTest()
        {
            Order order = _lazyLoading.EagerLoadOrderAggregateWithHQL(2);
            Assert.IsTrue(NHibernateUtil.IsInitialized(order.Customer));
            Assert.IsTrue(NHibernateUtil.IsInitialized(order.Products));
            Assert.AreEqual(order.Products.Count, 2);
        }

        #endregion
    }
}
